#include <cstring>
#include "TcpConnection.hpp"
#include "actions.hpp"

extern struct s_action		ft_actions[];
extern int			ft_nb_actions;

TcpConnection::pointer	TcpConnection::create(boost::asio::io_service &ios)
{
  return pointer(new TcpConnection(ios));
}

boost::asio::ip::tcp::socket&	TcpConnection::socket()
{
  return sock;
}

void		TcpConnection::start(const std::string &storage)
{
  st_path = storage;
  boost::asio::async_read(sock, boost::asio::buffer(header.buff),
			  boost::bind(&TcpConnection::handleRead, shared_from_this(),
				      boost::asio::placeholders::error));
}

void		TcpConnection::handleWrite(const boost::system::error_code &error)
{
  if (!error)
    {
      memset(&header.buff, 0, sizeof(header.buff));
      boost::asio::async_read(sock, boost::asio::buffer(header.buff),
			      boost::bind(&TcpConnection::handleRead, shared_from_this(),
					  boost::asio::placeholders::error));
    }
}

void		TcpConnection::handleRead(const boost::system::error_code &error)
{
  static int	sizeToRead = 0;
  static int	bufOffset = 0;

  if (!error)
    {
      if (DEBUG_MODE)
	std::cout << "recv: type " << header.rq.type
		  << ", data_sz " << header.rq.data_sz << std::endl;;
      std::cout << "------------Still to Read : " << sizeToRead << "--------------" << std::endl;
      if (currentCmd.type == 1)
	{
	  for (int i = 8; 0 != header.buff[i] && i < BUFSZ; ++i)
	    std::cout << header.buff[i];
	  std::cout << std::endl;
	}

      if (!sizeToRead)
	for (int i = ft_nb_actions - 1; i >= 0; --i)
	  {
	    if (ft_actions[i].id == header.rq.type || ft_actions[i].id == FT_REQ_INVALID)
	      {
		std::cout << "action " << i << std::endl;
		sizeToRead = header.rq.data_sz - 7;
		if (FT_REQ_INVALID)
		  sizeToRead = 0;
		currentCmd.type = header.rq.type;
		currentCmd.data_sz = header.rq.data_sz;
		action = i;
		break;
	      }
	  }
      else
	{
	  memcpy(&(buf[bufOffset]), header.buff, 8);
	  if (sizeToRead <= 8)
	    {
	      std::cout << "Read all data > processing cmd : " << buf << std::endl;
	      ft_actions[action].action(&(currentCmd), &(buf), st_path);
	      sizeToRead = 0;
	      bufOffset = 0;
	    }
	  else
	    {
	      sizeToRead -= 8;
	      bufOffset += 8;
	    }
	}

      if (header.rq.type != FT_REQ_CLEAN)
	{
	  if (DEBUG_MODE)
	    std::cout << "After, recv: type " << header.rq.type << ", data_sz " << header.rq.data_sz << std::endl;

	  boost::asio::async_write(sock, boost::asio::buffer(header.buff),
				   boost::bind(&TcpConnection::handleWrite, shared_from_this(),
					       boost::asio::placeholders::error));
	}
    }
}
